<?php
/**
 *
 * provides session data management services
 *
 * support mutiple shops and products
 *
 * @author Ben
 * @package Aramisauto
 */
class SessionCart
{
    /*
     * user object
     */
    public $user = null;

    /**
     * session name
     * @access public
     * @var string
     */
    public $sessionName = 'SessionCart';

    /**
     * session value
     * @access public
     * @var string
     */
    public $sessionValue = '';

    /**
     * shops
     * @access public
     * @var array
     */
    public $shops = array();

    /**
     * error code
     * @access public
     * @var integer
     */
    public $errCode = 0;

    /**
     * is empty
     * @access public
     * @var bool
     */
    public $isEmpty = true;


    /**
     * current shop id
     * @access public
     * @var integer
     */
    public $currentShopID = 0;

    /**
     * at the beginning, use this id as shop id
     * @access public
     * @var integer
     */
    public $defaultShopID = 0;

    /**
     * debug
     * @access public
     * @var bool
     */
    public $debug = true;

    /**
     * construct method
     *
     */
    public function __construct()
    {
        $this->user = sfContext::getInstance()->getUser();

        if ($this->user->hasAttribute($this->sessionName))
        {
//            $this->shops = unserialize(stripslashes($this->user->getAttribute($this->sessionName)));
            $this->shops = $this->user->getAttribute($this->sessionName);
            if (gettype($this->shops) == "array" && count($this->shops) > 0){
                $this->isEmpty = false;
            }
            else{
                $this->isEmpty = true;
            }
        } else {
            $this->isEmpty = true;
        }

        if ($this->isEmpty == false){
            foreach ($this->shops as $shopID => $shop_detail) {
                $this->currentShopID = $shopID;
                break;
            }
        }
        
        if ($this->isEmpty) { // initializing the shop, for only one shop
            $params = $this->createInfoStructure();
            $this->addShop($this->defaultShopID, $params);
        }
    }

    /**
     * create single instance of class
     *
     * @return object
     */
    public static function create()
    {
        // static associative array containing the real objects, key is classname
        static $instances = array();
        static $_count = 0;
        // get classname
        $class = __CLASS__;
        if (! array_key_exists($class, $instances)) {
            // does not yet exist, save in array
            $instances[$class] = new $class();
        }
        return $instances[$class];
    }

    /**
     * create shop structure
     *
     * @return array
     */
    public function createShopStructure()
    {
        $tmpShop = array();
        $tmpInfo      = $this->createInfoStructure();
        $tmpBuyerInfo = $this->createBuyerInfoStructure();
        $tmpOrder     = $this->createOrderStructure();
        $tmpShop = array(
                         'products'  => array(),
                         'info'      => $tmpInfo,
                         'buyerInfo' => $tmpBuyerInfo,
                         'order'     => $tmpOrder
                   );
        return $tmpShop;
    }

    /**
     * creat info structure
     *
     * @return array
     */
    public function createInfoStructure()
    {
        $tmpInfo = array('id' => '', 'currency' => '', 'languageID' => '');
        return $tmpInfo;
    }

    /**
     * create buyer info structure
     *
     * @return array
     */
    public function createBuyerInfoStructure()
    {
        $tmpInfo = array('id' => '');
        return $tmpInfo;
    }

    /**
     * creat order structure
     *
     * @return array
     */
    public function createOrderStructure()
    {
        $tmpInfo = array('amount' => 0, 'productsCount' => 0);
        return $tmpInfo;
    }

    /**
     * create product structure
     *
     * @return array
     */
    public function createProductStructure()
    {
        //vehicleKind => cohibaVehicle / robustoVehicle / stockVehicle
        $tmpProduct = array(
                 'vehicleView' => array(),
                 'options'     => array(),
        );
        return $tmpProduct;
    }

    /**
     * add shop
     *
     * @param integer $id
     * @param array $params
     * @return bool
     */
    public function addShop($id, $params)
    {
        if ($this->isEmpty || ! array_key_exists($id, $this->shops)) {
            $this->shops[$id] = $this->createShopStructure();
            $this->shops[$id]['info']['id'] = $id;
            $this->shops[$id]['info']['currency'] = $params['currency'];
            $this->shops[$id]['info']['languageID'] = $params['languageID'];
        }
        else {
            $this->errCode = 1;
        }
        
        $this->serializeSession();
        if (! $this->user->hasAttribute($this->sessionName)) {
            trigger_error('could not set session: ' . $this->sessionName . ' session value is: ' . $this->sessionValue, E_USER_ERROR);
        }

        $this->isEmpty = false;
        
        if ($this->errCode != 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * add buyer info in shop
     *
     * @param integer $shopID
     * @param array $params
     * @return bool
     */
    public function addShopBuyerInfo($shopID, $params)
    {
        $this->shops[$shopID]['buyerInfo']['ref'] = $params['ref'];
        $this->shops[$shopID]['buyerInfo']['nom'] = $params['nom'];
        $this->shops[$shopID]['buyerInfo']['prenom'] = $params['prenom'];
        $this->shops[$shopID]['buyerInfo']['email'] = $params['email'];
        $this->shops[$shopID]['buyerInfo']['isShowDetail'] = $params['isShowDetail'];
        $this->serializeSession();
        if (! $this->user->hasAttribute($this->sessionName)) {
            trigger_error('could not set session: ' . $this->sessionName . ' session value is: ' . $this->sessionValue, E_USER_ERROR);
        }
        if ($this->errCode != 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * update shop
     *
     * @param integer $id
     * @param array $params
     */
    public function updateShop($id, $params)
    {
        if (isset($this->shops[$id])) {
            if (is_array($params)) {
                $this->shops[$id]['info'] = $params;
            }
        }
        $this->serializeSession();
        if (! $this->user->hasAttribute($this->sessionName)) {
            trigger_error('could not set session: ' . $this->sessionName . ' session value is: ' . $this->sessionValue, E_USER_ERROR);
        }
    }

    /**
     * remove shop
     *
     * @param integer $id
     */
    public function removeShop($id)
    {
        if ($this->isExistedShop($id)) {
            if (isset($this->shops[$id])) {
                unset($this->shops[$id]);
            }
        }
        if (count($this->shops) == 0) {
            $this->isEmpty = true;
        }
        $this->serializeSession();
    }

    /**
     * add product
     *
     * @param integer $shopID
     * @param array $params
     * @return bool
     */
    public function addProduct($shopID, $params)
    {
        if ($this->isExistedShop($shopID)) {
           $this->addCommonProduct($shopID, $params);
        }
        $this->serializeSession();
        if (! $this->user->hasAttribute($this->sessionName)) {
            trigger_error('could not set session: ' . $this->sessionName . ' session value is: ' . $this->sessionValue, E_USER_ERROR);
        }
        if ($this->errCode != 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * remove product
     *
     * @param integer $shopID
     * @param integer $id
     * @param bool $reindex
     */
    public function removeProduct($shopID, $id, $reindex = false)
    {
        if ($this->isExistedShop($shopID)) {
            if (isset($this->shops[$shopID]['products'][$id])) {
                $this->shops[$shopID]['order']['amount'] -= $this->shops[$shopID]['products'][$id]['amount'];
                $this->shops[$shopID]['order']['productsCount'] --;
                unset($this->shops[$shopID]['products'][$id]);
            }
            if (count($this->shops[$shopID]['products']) == 0) {
                $this->shops[$shopID]['order']['amount'] = 0;
                $this->shops[$shopID]['order']['productsCount'] = 0;
                //				unset($this->shops[$shopID]);
            } else {
                if ($reindex) {
                    $this->reindexShopProducts($shopID);
                }
            }
        }
        $this->serializeSession();
    }

    /**
     * add product index
     *
     * @param integer $shopID
     * @param integer $productID
     * @return integer
     */
    public function getProductIndex($shopID, $productID)
    {
        $index = - 1;
        $i = 0;
        if ($this->isExistedShop($shopID)) {
            if (count($this->shops[$shopID]['products']) > 0) {
                foreach ($this->shops[$shopID]['products'] as $theProduct) {
                    if ($theProduct['id'] == $productID) {
                        $index = $i;
                        break;
                    }
                    $i ++;
                }
            }
        }
        return $index;
    }

    /**
     * get shop product by index
     *
     * @param integer $shopID
     * @param integer $index
     * @return array
     */
    public function getShopProductByIndex($shopID, $index)
    {
        if ($this->isExistedShop($shopID)) {
            if (array_key_exists($index, $this->shops[$shopID]['products'])) {
                return $this->shops[$shopID]['products'][$index];
            } else {
                return NULL;
            }
        } else {
            return NULL;
        }
    }

    /**
     * remove product by product id
     *
     * @param integer $shopID
     * @param integer $productID
     * @param bool $reindex
     */
    public function removeProductByProductID($shopID, $productID, $reindex = false)
    {
        $index = $this->getProductIndex($shopID, $productID);
        if ($index > - 1) {
            $this->removeProduct($shopID, $index, $reindex);
        }
    }

    /**
     * reindex shop products
     *
     * @param integer $shopID
     */
    public function reindexShopProducts($shopID)
    {
        if ($this->isExistedShop($shopID)) {
            $this->shops[$shopID]['products'] = array_values($this->shops[$shopID]['products']);
        }
        $this->serializeSession();
    }

    /**
     * sort products
     *
     * @param integer $shopID
     * @param string $sort_by
     * @param bool $serializeFlag
     */
    public function sortProducts($shopID, $sort_by = 'dateTime', $serializeFlag = false)
    {
        if ($this->isExistedShop($shopID)) {
            $productCount = count($this->shops[$shopID]['products']);
            $tmpProduct = array();
            if ($productCount > 0) {
                for ($i = $productCount; $i > 0; $i --) {
                    for ($j = 0; $j < $i; $j ++) {
                        $tmpProduct = $this->shops[$shopID]['products'][$j];
                        if (isset($this->shops[$shopID]['products'][$j + 1])) {
                            if ($sort_by === 'dateTime') {
                                if (($this->shops[$shopID]['products'][$j + 1]['dateStart'] < $this->shops[$shopID]['products'][$j]['dateStart']) || ($this->shops[$shopID]['products'][$j + 1]['dateStart'] == $this->shops[$shopID]['products'][$j]['dateStart'] && strtotime($this->shops[$shopID]['products'][$j + 1]['timeStart']) < strtotime($this->shops[$shopID]['products'][$j]['timeStart']))) {
                                    $this->shops[$shopID]['products'][$j] = $this->shops[$shopID]['products'][$j + 1];
                                    $this->shops[$shopID]['products'][$j + 1] = $tmpProduct;
                                }
                            }
                        }
                    }
                }
            }
            if ($serializeFlag) {
                $this->serializeSession();
            }
        }
    }

    /**
     * sort shops products
     *
     * @param string $sort_by
     */
    public function sortShopsProducts($sort_by = 'dateTime')
    {
        if (! $this->isEmpty) {
            foreach ($this->shops as $theShop) {
                $this->sortProducts($theShop['info']['id'], $sort_by, false);
            }
            $this->serializeSession();
        }
    }

    /**
     * remove all products
     *
     * @param integer $shopID
     */
    public function removeAllProducts($shopID)
    {
        if ($this->isExistedShop($shopID)) {
            if (isset($this->shops[$shopID]['products'])) {
                $this->shops[$shopID]['order']['amount'] = 0;
                $this->shops[$shopID]['order']['productsCount'] = 0;
                if (count($this->shops[$shopID]['products']) > 0) {
                    $this->shops[$shopID]['products'] = array();
                }
            }
        }
        $this->serializeSession();
    }

    /**
     * add common product
     *
     * @param integer $shopID
     * @param integer $params
     */
    public function addCommonProduct($shopID, $params)
    {
        if ($this->isExistedShop($shopID)) {
            $tmpProduct = $this->createProductStructure();
            $tmpProduct['vehicleView'] = array(
                                              'id'=>$params['id'],
                                              'price'=>$params['price'],
                                         );
            
            $tmpProduct['options'] = array();
            
            if (! $this->isExistedShopProduct($shopID, $tmpProduct)) {
//                $this->shops[$shopID]['order']['amount'] += $tmpProducts['amount'];
                $this->shops[$shopID]['order']['productsCount'] ++;
                $this->shops[$shopID]['products'][] = $tmpProduct;
            }
        }
    }

    /**
     * is shop existed
     *
     * @param integer $id
     * @return integer/bool
     */
    public function isExistedShop($id)
    {
        if (! $this->isEmpty) {
            return array_key_exists($id, $this->shops);
        } else
            return false;
    }

    /**
     * is shop product existed
     *
     * @param integer $shopID
     * @param array $params
     * @return bool
     */
    public function isExistedShopProduct($shopID, $params)
    {
        if (isset($this->shops[$shopID]['products'])) {
            $flag = false;
            if (count($this->shops[$shopID]['products']) > 0) {
                foreach ($this->shops[$shopID]['products'] as $theProduct) {
                    if ($theProduct['id'] == $params['id']) {
                        $flag = true;
                        break;
                    }
                }
            }
            return $flag;
        } else
            return false;
    }

    /**
     * reset shop
     *
     */
    public function resetShop()
    {
        reset($this->shops);
    }

    /**
     * count shop
     *
     * @return integer
     */
    public function countShop()
    {
        if (!$this->isEmpty) {
            return count($this->shops);
        } else {
            return 0;
        }
    }

    /**
     * get count of shop products
     *
     * @param integer $shopID
     * @return integer
     */
    public function getShopProductsCount($shopID)
    {
        if ($this->isExistedShop($shopID)) {
            return $this->shops[$shopID]['order']['productsCount'];
        } else {
            return 0;
        }
    }

    /**
     * remove all shops
     *
     */
    public function removeAllShops()
    {
        $this->shops = array();
        if ($this->user->hasAttribute($this->sessionName)) {
           $this->user->getAttributeHolder()->remove($this->sessionName);
        }
        $this->isEmpty = true;
    }

    /**
     * set name of cart
     *
     * @param string $value
     */
    public function setCartName($value)
    {
        $this->sessionName = $value;
    }

    /**
     * print debug info
     *
     * @param bool $varFlag
     * @return string
     */
    public function printOut($varFlag = false)
    {
        if ($this->debug) {
            $tmpStr = '';
            $tmpStr .= "<h3>{$this->sessionName} Debug Info:</h3><br/>" . str_repeat('=', 100) . '<br/>';
            $tmpStr .= nl2br(print_r($this->shops, true));
            if (! $varFlag) {
                echo $tmpStr;
            } else {
                return $tmpStr;
            }
        }
    }

    /**
     * add shashes to data
     *
     * @param array $val
     * @param string $key
     */
    public function addSlashesData(&$val, $key)
    {
        if (is_array($val)) {
            array_walk($val, array(&$this, 'addSlashesData'));
        } else {
            $val = addslashes($val);
        }
    }

    /**
     * strip slashes from data
     *
     * @param array $val
     * @param string $key
     */
    public function stripSlashesData(&$val, $key)
    {
        if (is_array($val)) {
            array_walk($val, array(&$this, 'stripSlashesData'));
        } else {
            $val = stripslashes($val);
        }
    }

    /**
     * serialize session
     *
     */
    public function serializeSession()
    {
//        $this->sessionValue = serialize($this->shops);
//        $this->user->setAttribute($this->sessionName, $this->sessionValue);
        $this->user->setAttribute($this->sessionName, $this->shops);
    }

    /**
     * get total amount
     *
     * @return integer
     */
    public function getTotalAmount()
    {
        $totalAmount = 0;
        foreach ($this->shops[$this->currentShopID]["products"] as $theProduct) {
            $totalAmount += $theProduct["amount"];
        }
        return $totalAmount;
    }

    /**
     * get list of existed product id of shop
     *
     * @param integer $shopID
     * @param bool $isToString
     * @return array / string
     */
    public function getExistedProductIDs($shopID, $isToString = false)
    {
        $tmpArr = array();
        if ($this->isExistedShop($shopID)) {
            foreach ($this->shops[$shopID]["products"] as $theProduct) {
                $tmpArr[] = $theProduct["id"];
            }
        }
        if ($isToString) {
            return implode(',', $tmpArr);
        } else {
            return $tmpArr;
        }
    }

    /**
     * get order string with JSON format
     *
     * @param integer $shopID
     * @return string
     */
    public function getShopJsonOrderString($shopID)
    {
        if ($this->isExistedShop($shopID)) {
            return json_encode($this->shops[$shopID]['order']);
        }
    }

    /**
     * get product string with JSON format
     *
     * @param integer $shopID
     * @return string
     */
    public function getShopJsonProductsString($shopID)
    {
        if ($this->isExistedShop($shopID)) {
            return json_encode($this->shops[$shopID]['products']);
        }
    }
}
?>